package handle

import (
	"cc/utils"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"
)

type DropReq struct {
	User   string `json:"user"`
	Color  string `json:"color"`
	XPoint int    `json:"x_point"`
	YPoint int    `json:"y_point"`
}
type UserData struct {
	state bool
	color string
}
type RoomRes struct {
	Name  string `json:"name"`
	Count int    `json:"count"`
}
type ChannelData struct {
	operate string
	data    any
}

type SelectReq struct {
	User  string `json:"user"`
	Color string `json:"color"`
}
type checkData struct {
	Drop         DropReq `json:"drop,omitempty"`
	ReadyState   bool    `json:"ready_state"`
	Color        string  `json:"color"`
	CurrentColor string  `json:"current_color"`
}
type CheckRes struct {
	State string    `json:"state"`
	Data  checkData `json:"data,omitempty"`
}

var mu sync.Mutex
var channels = make(map[string]chan ChannelData)

// 定义一个处理 HTTP 请求的函数
func OpenHandler(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/open/"), "/")
	ch := make(chan ChannelData)
	roomId := path[0]

	// 存储 channel 到 map 中
	mu.Lock()
	if channels[roomId] != nil {
		http.Error(w, "room "+roomId+" had existed", http.StatusInternalServerError)
		mu.Unlock()
		return
	}
	channels[roomId] = ch
	mu.Unlock()

	// 启动一个 room 来监听这个 channel
	go func() {
		timeout := time.NewTimer(30 * time.Minute)
		members := make(map[string]*UserData)
		readyCount := 0
		master := ""
		currentColor := "white"
		checkList := []*DropReq{}
		var lastCheck *DropReq = nil
		state := "waiting"

		defer func() {
			timeout.Stop()           // 确保停止计时器
			close(ch)                // 关闭通道
			delete(channels, roomId) // 删除房间
			fmt.Printf("%s delete %s\n", time.Now().Format("2006-01-02 15:04:05"), roomId)
		}()

		for {
			select {
			case msg, ok := <-ch:
				if !ok {
					return
				}
				mu.Lock()
				// 每当收到消息，打印出来
				fmt.Printf("room %v received: %v\n", roomId, msg)
				switch msg.operate {
				case "get":
					ch <- ChannelData{
						operate: "ok",
						data: RoomRes{
							Name:  roomId,
							Count: len(members),
						},
					}
				case "join":
					user, ok := msg.data.(string)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse user",
						}
						return
					}
					if master == "" {
						master = user
					}

					_, exist := members[user]
					if exist {
						ch <- ChannelData{
							operate: "reload",
							data:    "Reload had already in the room",
						}
						break
					}
					if len(members) >= 2 {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error can not enter room full",
						}
						break
					}
					members[user] = &UserData{state: false}
					timeout.Reset(30 * time.Minute)
					fmt.Printf("%v joinned\n", user)

					ch <- ChannelData{operate: "ok"}
				case "drop":
					dr, ok := msg.data.(DropReq)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse DropReq",
						}
						break
					}
					player, exist := members[dr.User]
					if !exist {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error had already in the room",
						}
						break
					}
					if state != "gamming" {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error game not started",
						}
						break
					}
					if player.color != currentColor {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error it is not your round",
						}
						break
					}
					if lastCheck != nil && lastCheck.User == dr.User {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error can't check in same people",
						}
						break
					}
					dr.Color = currentColor
					if currentColor == "black" {
						currentColor = "white"
					} else {
						currentColor = "black"
					}
					fmt.Printf("checkList: %v\n", checkList)
					lastCheck = &dr
					checkList = append(checkList, &dr)
					ch <- ChannelData{operate: "ok", data: nil}
				case "exit":
					user, ok := msg.data.(string)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse user",
						}
						break
					}
					_, exist := members[user]
					if !exist {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error user not contain",
						}
						break
					}
					delete(members, user)
					if len(members) == 0 {
						timeout.Reset(1 * time.Minute)
					}
					ch <- ChannelData{operate: "ok"}
				case "check":
					user, ok := msg.data.(string)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse user",
						}
						break
					}
					player, exist := members[user]
					if !exist {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error user not exist in room",
						}
						break
					}
					var cr *DropReq
					if len(checkList) == 0 {
						cr = &DropReq{}
					} else {
						cr = checkList[len(checkList)-1]
					}
					checkData := checkData{
						Drop:         *cr,
						ReadyState:   player.state,
						Color:        player.color,
						CurrentColor: currentColor,
					}
					ch <- ChannelData{
						operate: "ok",
						data: CheckRes{
							State: state,
							Data:  checkData,
						},
					}
				case "ready":
					user, ok := msg.data.(string)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse user",
						}
						break
					}
					player, exist := members[user]
					if !exist {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error user not exist",
						}
						break
					}
					if state != "waiting" {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error game is " + state,
						}
						break
					}
					if player.state {
						player.state = false
						readyCount -= 1
					} else {
						player.state = true
						readyCount += 1
						if readyCount == 2 {
							state = "select"
						}
					}
					ch <- ChannelData{operate: "ok", data: nil}
				case "select":
					dr, ok := msg.data.(SelectReq)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse DropReq",
						}
						break
					}
					if state != "select" {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error game cant select",
						}
						break
					}
					player, exist := members[dr.User]
					if !exist {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error user not exist",
						}
						break
					}
					player.color = dr.Color
					for k, v := range members {
						if k != dr.User {
							if dr.Color == "white" {
								v.color = "black"
							} else {
								v.color = "white"
							}
						}
					}
					ch <- ChannelData{operate: "ok"}
					state = "gamming"
				case "history":
					user, ok := msg.data.(string)
					if !ok {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error parse user",
						}
						break
					}
					_, exist := members[user]
					if !exist {
						ch <- ChannelData{
							operate: "fail",
							data:    "Error user not exist in room",
						}
						break
					}
					ch <- ChannelData{
						operate: "ok",
						data:    checkList,
					}
				}

				mu.Unlock()
			case <-timeout.C: // 超时处理
				return
			}

		}
	}()
	fmt.Fprintf(w, "%s", "open room "+roomId)
}

func DropHandler(w http.ResponseWriter, r *http.Request) {
	// if r.Method != http.MethodPost {
	// 	http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
	// 	return
	// }
	// 获取对应的 channel
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/drop/"), "/")
	roomId := path[0]
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()

	if !exists {
		fmt.Printf("room %s does not exist!\n", path)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	body, err := io.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Error reading request body", http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()
	// 向 room 发送消息
	fmt.Printf("body: %v\n", body)
	var dropReq DropReq
	err = json.Unmarshal(body, &dropReq)
	if err != nil {
		http.Error(w, "Error parsing JSON??", http.StatusBadRequest)
		return
	}
	cd := ChannelData{
		operate: "drop",
		data:    dropReq,
	}
	ch <- cd
	cr := <-ch
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}

}

func JoinHandler(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/join/"), "/")
	if len(path) == 0 {
		http.Error(w, "no room", http.StatusBadRequest)
	}
	if len(path) == 1 {
		http.Error(w, "no user", http.StatusBadRequest)
	}
	roomId, user := path[0], path[1]

	cd := ChannelData{
		operate: "join",
		data:    user,
	}
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()

	if !exists {
		fmt.Printf("room %s does not exist!\n", path)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	ch <- cd
	cr := <-ch
	if cr.operate == "reload" {
		msg, _ := cr.data.(string)
		fmt.Fprintf(w, "%s", ""+msg)
		return
	}
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "%s", "join user "+user)
}
func ExitHandler(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/exit/"), "/")
	if len(path) == 0 {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
	}
	if len(path) == 1 {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
	}
	roomId, user := path[0], path[1]
	cd := ChannelData{
		operate: "exit",
		data:    user,
	}
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()
	if !exists {
		fmt.Printf("room %s does not exist!\n", path)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	ch <- cd
	cr := <-ch
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "%s", roomId+" exit user "+user)
}

func CheckHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/check/"), "/")
	if len(path) == 0 {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
	}
	if len(path) == 1 {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
	}
	roomId, user := path[0], path[1]
	cd := ChannelData{
		operate: "check",
		data:    user,
	}
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()
	if !exists {
		fmt.Printf("room %s does not exist!\n", path)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	ch <- cd
	cr := <-ch
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}
	jsonData, err := json.Marshal(cr.data)
	if err != nil {
		// 如果序列化失败，返回错误信息
		http.Error(w, "Failed to marshal JSON", http.StatusInternalServerError)
		return
	}

	// 写入 JSON 数据到 HTTP 响应体
	w.Write(jsonData)
}
func RoomHandler(w http.ResponseWriter, r *http.Request) {
	cs := utils.GetMapKeys(channels)
	var data []RoomRes
	for _, v := range cs {
		cd := ChannelData{
			operate: "get",
		}
		mu.Lock()
		ch, exists := channels[v]
		mu.Unlock()
		if !exists {
			fmt.Printf("room %s does not exist!\n", v)
			return
		}
		ch <- cd
		cr := <-ch
		if cr.operate != "ok" {
			msg, _ := cr.data.(string)
			http.Error(w, msg, http.StatusBadRequest)
			return
		}
		rr, _ := cr.data.(RoomRes)
		fmt.Printf("v: %v\n", v)
		data = append(data, rr)
	}
	fmt.Printf("data: %v\n", data)
	jsonData, err := json.Marshal(data)
	if err != nil {
		// 如果序列化失败，返回错误信息
		http.Error(w, "Failed to marshal JSON", http.StatusInternalServerError)
		return
	}

	// 写入 JSON 数据到 HTTP 响应体
	w.Write(jsonData)
}

func ReadyHandler(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/ready/"), "/")
	if len(path) == 0 {
		http.Error(w, "no room", http.StatusBadRequest)
	}
	if len(path) == 1 {
		http.Error(w, "no user", http.StatusBadRequest)
	}
	roomId, user := path[0], path[1]
	cd := ChannelData{
		operate: "ready",
		data:    user,
	}
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()
	if !exists {
		fmt.Printf("room %s does not exist!\n", roomId)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	ch <- cd
	cr := <-ch
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}
}

func SelectHandler(w http.ResponseWriter, r *http.Request) {
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/select/"), "/")
	roomId := path[0]
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()

	if !exists {
		fmt.Printf("room %s does not exist!\n", path)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	body, err := io.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Error reading request body", http.StatusInternalServerError)
		return
	}
	defer r.Body.Close()
	// 向 room 发送消息
	fmt.Printf("body: %v\n", body)
	var selectReq SelectReq
	err = json.Unmarshal(body, &selectReq)
	if err != nil {
		http.Error(w, "Error parsing JSON??", http.StatusBadRequest)
		return
	}
	cd := ChannelData{
		operate: "select",
		data:    selectReq,
	}
	ch <- cd
	cr := <-ch
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}

}

func HistoryHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	path := strings.Split(strings.TrimPrefix(r.URL.Path, "/history/"), "/")
	if len(path) == 0 {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
	}
	if len(path) == 1 {
		http.Error(w, "Error parsing JSON", http.StatusBadRequest)
	}
	roomId, user := path[0], path[1]
	cd := ChannelData{
		operate: "history",
		data:    user,
	}
	mu.Lock()
	ch, exists := channels[roomId]
	mu.Unlock()
	if !exists {
		fmt.Printf("room %s does not exist!\n", path)
		http.Error(w, "room "+roomId+" does not exist!\n", http.StatusBadRequest)
		return
	}
	ch <- cd
	cr := <-ch
	if cr.operate != "ok" {
		msg, _ := cr.data.(string)
		http.Error(w, msg, http.StatusBadRequest)
		return
	}
	jsonData, err := json.Marshal(cr.data)
	if err != nil {
		// 如果序列化失败，返回错误信息
		http.Error(w, "Failed to marshal JSON", http.StatusInternalServerError)
		return
	}

	// 写入 JSON 数据到 HTTP 响应体
	w.Write(jsonData)
}
